#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <linux/fb.h>

int main(int argc, char const *argv[])
{
    // 1. 打开LCD设备
    int lcd = open("/dev/fb0", O_RDWR);

    // 2. 获取LCD硬件参数并映射内存
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);
    ioctl(lcd, FBIOGET_FSCREENINFO, &finfo);

    int width = vinfo.xres; // LCD的宽
    int height= vinfo.yres; // LCD的高
    int bpp   = vinfo.bits_per_pixel; // LCD的色深（即每个像素点对应的字节数）
    int screensize = width * height * bpp/8; // LCD整屏对应的内存的大小

    char *p = mmap(NULL, screensize*2, PROT_WRITE, MAP_SHARED, lcd, 0);
    if(p == MAP_FAILED)
    {
        perror("映射内存失败");
        exit(0);
    }

    // 3. 设定可见区
    vinfo.xoffset = 0;
    vinfo.yoffset = 0;
    ioctl(lcd, FBIOPAN_DISPLAY, &vinfo);

    uint32_t colors[] = {0x00FF0000, 0x0000FF00, 0x000000FF};
    //                       红          绿          蓝

    for(int i=1; ; i++)
    {
        // 4. 将操作内存入口设定为另一个区
        char *tmp = p + screensize*(i%2);

        // 绘制一屏
        for(int h=0; h<height; h++)
        {
            // 绘制一行
            for(int w=0; w<width; w++)
                memcpy(tmp + 4*w + 800*4*h, &colors[i%3], 4);
        }

        // 5. 更新可见区
        vinfo.xoffset = 0;
        vinfo.yoffset = 480 * (i%2);
        ioctl(lcd, FBIOPAN_DISPLAY, &vinfo);

        sleep(1);
    }



    return 0;
}
